using System;
using System.Text;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;

namespace HB.CacheDb
{
    public static class QueryExpand
    {
        public static T DeepCopyByReflection<T>(this T oldv) where T : class, new()
        {
            Type type = typeof(T);
            var ps = type.GetProperties();
            T newv = new T();
            foreach (var p in ps)
            {
                p.SetValue(newv, p.GetValue(oldv, null), null);
            }
            return newv;
        }

        public static string CreateDeepCopyFuncCode<T>()
        {
            Type t = typeof(T);
            StringBuilder sb = new StringBuilder();
            sb.Append($"t=>new {t.Name }()"); sb.Append("{");
            foreach (var p in t.GetProperties())
            {
                sb.Append($"{p.Name }=t.{p.Name }"); sb.Append(",");
            }
            sb.Append("}");
            return sb.ToString();
        }
        public static Func<T, T> CompileDeepCopy<T>()
        {
            List<Assembly> lsass = new List<Assembly>();
            List<string> lsimp = new List<string>();
            var t = typeof(T);
            lsass.Add(typeof(T).Assembly);
            lsimp.Add(typeof(T).Namespace);
            StringBuilder sb = new StringBuilder();
            sb.Append($"t=> new {t.Name }()"); sb.Append("{");
            foreach (var p in t.GetProperties())
            {
                if (p.CanWrite)
                {
                    if (!lsass.Where(zz => zz.FullName != p.PropertyType.FullName).Any())
                    {
                        lsass.Add(p.PropertyType.Assembly);

                    }
                    if (!lsimp.Contains(p.PropertyType.Namespace))
                    {
                        lsimp.Add(p.PropertyType.Namespace);
                    }
                    sb.Append($"{p.Name }=t.{p.Name }"); sb.Append(",");
                }
            }
            sb.Append("}");
             var f = CSharpScript.EvaluateAsync<Func<T, T>>(sb.ToString(), ScriptOptions.Default.WithImports(lsimp.ToArray()).WithReferences(lsass.ToArray())).Result;
            GC.Collect();
            return f;
            }
    }
}